﻿using System;
using System.Collections.Generic;
using DimOS.Constants;
using DimOS.DimSH;
using DimOS.Internals;
using SH = DimOS.DimSH.Shell;
using UI = DimOS.DimSH.Interface;
using TERM = DimOS.DimSH.Terminal;

namespace DimOS.H
{
    public static class Engine
    {
        public static int ProcessLimit = UI.OutputColumns;
        public static int OutputLimit = 10;
        public static bool Footer;

        public static Value Input(List<CharColor> customPrompt = null)
        { var input = SH.Prompt(0, UI.OutputColumns - 1, UI.Rows - 1,
          -1, false, true, customPrompt, false, false, false); return
          new Value(/*String.Mirror(*/input/*, Tokens.VerbatimString)*/); }

        public static void Output(string output)
        { if (!Footer) { TERM.WriteLine(); Footer = true; } if (UI.X != 0 && output.Length
          > UI.OutputColumns - UI.X) { var temp = output.Substring(0, UI.OutputColumns - UI
          .X); TERM.WriteLine(temp, false, false, true, false); output = output.Substring
          (temp.Length); if (temp.Length != 0 && output[0] == Tokens.Space) output = output
          .Remove(0, 1); } TERM.Write(output, true, true, true); }

        public static void Header(string command, List<string> parameters = null)
        {
            if (!Footer) { TERM.WriteLine(); Footer = true; } UI.Foreground = Colors.PromptEnclosure;
            TERM.Write(Separators.PromptBraceLeft, false); UI.Foreground = Colors.OutputCommand; TERM
            .Write(command, false); UI.Foreground = Colors.OutputArgs; if (parameters != null) for (int
            i = 0; i < parameters.Count; i++) TERM.Write(" " + parameters[i], false); UI.Foreground =
            Colors.PromptEnclosure; TERM.Write(Separators.PromptBraceRight, false); UI.Foreground = SH
            .AccessMode == Account.Root ? Colors.PromptIndicatorRoot : Colors.PromptIndicatorUser; TERM
            .Write(SH.AccessMode == Account.Root ? Separators.IndicatorRoot : Separators.IndicatorUser,
            false); UI.Foreground = Colors.PromptEnclosure; TERM.Write(Separators.PromptSpecifier, false);
            TERM.WriteLine(Tokens.NewLine.ToString()); UI.Foreground = Colors.SectionOutputForeground;
        }

        public static void Wait(int seconds){ TERM.Wait(seconds); }

        public static void Initialize()
        {
            for (int i = 0; i < Commands.List[0].Count; i++)
            Function.Add(Commands.List[0][i].Key, new Shell());

            Function.Add(Tokens.Else, new SafetyPlug());
            Function.Add(Tokens.ElseIf, new SafetyPlug());
            Function.Add(Tokens.ElseShort, new SafetyPlug());

            Function.Add(Tokens.If, new Conditional());
            Function.Add(Tokens.IfShort, new Conditional());
            Function.Add(Tokens.Try, new Try());
            Function.Add(Tokens.TryShort, new Try());

            Function.Add(Tokens.Terminal, new InputOutput());
            Function.Add(Tokens.TerminalShort.ToString(), new InputOutput());
            Function.Add(Tokens.Substring, new Substring());
            Function.Add(Tokens.SubstringShort, new Substring());
            Function.Add(Tokens.Replace, new Replace());
            Function.Add(Tokens.ReplaceShort, new Replace());

            Function.Add(Tokens.Loop, new Loop());
            Function.Add(Tokens.LoopShort.ToString(), new Loop());
            Function.Add(Tokens.Break, new Break());
            Function.Add(Tokens.BreakShort, new Break());
            Function.Add(Tokens.Continue, new Continue());
            Function.Add(Tokens.ContinueShort, new Continue());

            Function.Add(Tokens.Define, new New());
            Function.Add(Tokens.DefineShort.ToString(), new New());
            Function.Add(Tokens.Return, new Return());
            Function.Add(Tokens.ReturnShort, new Return());
            Function.Add(Tokens.Throw, new Throw());
            Function.Add(Tokens.ThrowShort, new Throw());

            Function.Add(Tokens.Wait, new Wait());
            Function.Add(Tokens.WaitShort, new Wait());
            Function.Add(Tokens.Size, new Size());
            Function.Add(Tokens.SizeShort.ToString(), new CombinedSize());
            Function.Add(Tokens.Type, new Type());

            Function.Add(Tokens.SquareRoot, new SquareRoot());
            Function.Add(Tokens.Absolute, new Absolute());
            Function.Add(Tokens.Round, new Round());
            Function.Add(Tokens.Ceiling, new Ceiling());
            Function.Add(Tokens.Floor, new Floor());

            Function.AddOperation(Tokens.Assignment.ToString(), new Assignment());
            Function.AddOperation(Tokens.Increment, new IncDec());
            Function.AddOperation(Tokens.Decrement, new IncDec());
            Function.AddOperation(Tokens.Sort, new SortReverse());
            Function.AddOperation(Tokens.Reverse, new SortReverse());
            Function.AddOperation(Tokens.InputRedirect, new InputRedirect());

            Function.AddOperation(Tokens.AddAssignment, new CombinedAssignment());
            Function.AddOperation(Tokens.SubtractAssignment, new CombinedAssignment());
            Function.AddOperation(Tokens.MultiplyAssignment, new CombinedAssignment());
            Function.AddOperation(Tokens.DivideAssignment, new CombinedAssignment());
            Function.AddOperation(Tokens.PowerAssignment, new CombinedAssignment());
            Function.AddOperation(Tokens.RemainderAssignment, new CombinedAssignment());
            Function.AddOperation(Tokens.IndexAssignment, new CombinedAssignment());
            Function.AddOperation(Tokens.ConvertAssignment, new CombinedAssignment());
           
            Function.AddVariable(Tokens.Pi, new Variable(new Value((float)Math.PI)));
            
            for (int k = 0; k < Functions.List.Count; k++)
            Functions.Core.Add(Functions.List[k].Clone());


            //Prompt = new List<CharColor> { new CharColor (Separators.PromptBraceLeft, Colors
            //.PromptEnclosure, Colors.SectionOutputBackground) }; for (int j = 0; j < Separators
            //.DimL.Length; j++) Prompt.Add(new CharColor(Separators.DimL[j], Colors.Prompt, Colors
            //.SectionOutputBackground)); Prompt.Add(new CharColor(Separators.PromptBraceRight,
            //Colors.PromptEnclosure, Colors.SectionOutputBackground)); Prompt.Add(new CharColor
            //(Separators.PromptSpecifier, Colors.Specifier, Colors.SectionOutputBackground)); Prompt
            //.Add(new CharColor(' ', Colors.SectionOutputForeground, Colors.SectionOutputBackground));
        }

        public static Value Process(string source, ref List<Error> errors)
        {
            source = Script.Normalize(source, ref errors); var result = Value.Empty; if
            (string.IsNullOrWhiteSpace(source)) return result; var script = new Script
            (source); try { while (script.Pointer < source.Length) { result = script
            .Execute(); script.Proceed(); } } catch (Exception exception) { UI.Foreground
            = Colors.IndicatorInputInvalid; if (!Footer) { TERM.WriteLine(); Footer = true;
            UI.X = 0; } TERM.Write("Exception: " + exception.Message); } Functions.List
            .Clear(); Functions.Stack.Clear(); for (int index = 0; index < Functions.Core
            .Count; index++) Functions.List.Add(Functions.Core[index].Clone()); if (Footer)
            { if (UI.X != 0) TERM.WriteLine(); UI.DrawSectionSplitter(); Footer = false;
            UI.X = 0; } UI.Foreground = Colors.SectionOutputForeground; return result;
        }

        public static List<Error> Check(string source)
        {
            var inputErrors = new List<Error>(); source = Script.Normalize(source, ref
            inputErrors); if (string.IsNullOrWhiteSpace(source)) { SH.InputIndicatorColor
            = Colors.IndicatorInputDefault; UI.DrawInputIndicator(SH.InputIndicatorColor);
            return inputErrors; } var valid = new Script(source).CheckAll(); if (!valid)
            SH.InputIndicatorColor = Colors.IndicatorInputInvalid; else if (inputErrors
            .Count != 0) SH.InputIndicatorColor = Colors.IndicatorInputWarning; else SH
            .InputIndicatorColor = Colors.IndicatorInputValid; UI.DrawInputIndicator(SH
            .InputIndicatorColor); return inputErrors;
        }
    }
}
